/**
 * MongoDB 实现（可选）
 */
import { BaseDatabase, DatabaseConfig, QueryOptions, QueryResult } from './base';
import { MongoClient, Db, ObjectId } from 'mongodb';

export class MongoDatabase extends BaseDatabase {
  private client?: MongoClient;
  private db?: Db;

  async connect(): Promise<void> {
    if (this.connected) return;
    const uri = this.config.connectionString || process.env.MONGODB_URI || 'mongodb://localhost:27017';
    const dbName = (this.config.options?.dbName) || process.env.MONGODB_DB || 'aigc';
    this.client = new MongoClient(uri);
    await this.client.connect();
    this.db = this.client.db(dbName);
    this.connected = true;
  }

  async disconnect(): Promise<void> {
    if (this.client) {
      await this.client.close();
      this.client = undefined;
      this.db = undefined;
    }
    this.connected = false;
  }

  isConnected(): boolean { return this.connected; }

  async create<T>(collection: string, data: Partial<T>): Promise<QueryResult<T>> {
    try {
      if (!this.db) await this.connect();
      const res = await this.db!.collection(collection).insertOne(data as any);
      return { success: true, data: { ...(data as any), _id: res.insertedId } };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async createMany<T>(collection: string, data: Partial<T>[]): Promise<QueryResult<T[]>> {
    try {
      if (!this.db) await this.connect();
      const res = await this.db!.collection(collection).insertMany(data as any);
      const inserted = data.map((d, i) => ({ ...(d as any), _id: (res.insertedIds as any)[i] }));
      return { success: true, data: inserted as any };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async findOne<T>(collection: string, filter: Record<string, any>): Promise<QueryResult<T>> {
    try {
      if (!this.db) await this.connect();
      const res = await this.db!.collection(collection).findOne(filter as any) as any;
      return { success: true, data: res as T };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async findMany<T>(collection: string, filter: Record<string, any> = {}, options: QueryOptions = {}): Promise<QueryResult<T[]>> {
    try {
      if (!this.db) await this.connect();
      const page = Math.max(1, options.page || 1);
      const pageSize = Math.min(100, Math.max(1, options.pageSize || 20));
      const cursor = this.db!.collection(collection).find(filter as any);
      if (options.sortBy) cursor.sort({ [options.sortBy]: options.sortOrder === 'asc' ? 1 : -1 });
      const data = await cursor.skip((page - 1) * pageSize).limit(pageSize).toArray();
      return { success: true, data: data as any };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async update<T>(collection: string, filter: Record<string, any>, data: Partial<T>): Promise<QueryResult<T>> {
    try {
      if (!this.db) await this.connect();
      const res = await this.db!.collection(collection).findOneAndUpdate(filter as any, { $set: data }, { returnDocument: 'after' });
      return { success: true, data: res.value as any };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async updateMany<T>(collection: string, filter: Record<string, any>, data: Partial<T>): Promise<QueryResult<number>> {
    try {
      if (!this.db) await this.connect();
      const res = await this.db!.collection(collection).updateMany(filter as any, { $set: data });
      return { success: true, data: res.modifiedCount };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async delete(collection: string, filter: Record<string, any>): Promise<QueryResult<boolean>> {
    try {
      if (!this.db) await this.connect();
      const res = await this.db!.collection(collection).deleteOne(filter as any);
      return { success: true, data: res.deletedCount === 1 };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async deleteMany(collection: string, filter: Record<string, any>): Promise<QueryResult<number>> {
    try {
      if (!this.db) await this.connect();
      const res = await this.db!.collection(collection).deleteMany(filter as any);
      return { success: true, data: res.deletedCount || 0 };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async count(collection: string, filter: Record<string, any> = {}): Promise<QueryResult<number>> {
    try {
      if (!this.db) await this.connect();
      const cnt = await this.db!.collection(collection).countDocuments(filter as any);
      return { success: true, data: cnt };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async createIndex(collection: string, fields: Record<string, any>): Promise<QueryResult<boolean>> {
    try {
      if (!this.db) await this.connect();
      await this.db!.collection(collection).createIndex(fields);
      return { success: true, data: true };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async dropCollection(collection: string): Promise<QueryResult<boolean>> {
    try {
      if (!this.db) await this.connect();
      await this.db!.collection(collection).drop();
      return { success: true, data: true };
    } catch (e: any) { return { success: false, error: e.message }; }
  }

  async listCollections(): Promise<QueryResult<string[]>> {
    try {
      if (!this.db) await this.connect();
      const cols = await this.db!.listCollections().toArray();
      return { success: true, data: cols.map(c => c.name) };
    } catch (e: any) { return { success: false, error: e.message }; }
  }
}

export default MongoDatabase;